package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import com.cloudfun.campusshare.common.constant.*;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.AuditDTO;
import com.cloudfun.campusshare.common.model.dto.LoanDTO;
import com.cloudfun.campusshare.common.model.dto.LoanIssueDTO;
import com.cloudfun.campusshare.common.model.dto.LoanQueryDTO;
import com.cloudfun.campusshare.common.model.vo.*;
import com.cloudfun.campusshare.common.response.BaseResult;
import com.cloudfun.campusshare.common.response.BaseResultFactory;
import com.cloudfun.campusshare.common.response.PageResult;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.*;
import com.cloudfun.campusshare.repo.ApplicationEntityRepo;
import com.cloudfun.campusshare.repo.LoanEntityRepo;
import com.cloudfun.campusshare.repo.ProjectEntityRepo;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.service.ApplicationService;
import com.cloudfun.campusshare.service.AttachmentService;
import com.cloudfun.campusshare.service.LoanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.validation.ConstraintViolationException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Huqin on 2020/3/4
 */
@Slf4j
@Service
public class LoanServiceImpl implements LoanService {

    @Autowired
    private LoanEntityRepo loanEntityRepo;

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Autowired
    private AttachmentService attachmentService;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ApplicationEntityRepo applicationEntityRepo;

    @Autowired
    private ProjectEntityRepo projectEntityRepo;

    @Override
    @Transactional
    public BaseResult<?> createDraft(LoanDTO loanDTO) {
        LoanEntity loanEntity = this.loadOrCreate(loanDTO);
        if (null != loanEntity.getStatus() && !LoanStatus.CREATING.equals(loanEntity.getStatus())) {
            throw new BusinessException(Code.DUPLICATE_APPLICATION);
        }
        // 设置状态
        loanEntity.setStatus(LoanStatus.CREATING);
        // 保存草稿
        loanEntityRepo.save(loanEntity);
        // 设置附件
        this.setAttach(loanEntity.getId(), loanDTO.getAttachIdList());
        // 设置项目
        this.setProject(loanEntity, loanDTO.getProjectIds());
        return BaseResultFactory.produceResult(Code.SUCCESS, loanEntity.getId());
    }

    private void setAttach(String loanId, List<String> attachIds) {
        if (!CollectionUtils.isEmpty(attachIds)) {
            // 关联附件
            attachmentService.relateAttachment(loanId, attachIds, AttachType.ASSET_SUMMARY_LIST);
        }
    }

    private void setProject(LoanEntity loanEntity, List<String> projectIds) {
        if (CollectionUtils.isEmpty(projectIds)) {
            return;
        }
        List<ProjectEntity> oldProjectEntities = projectEntityRepo.findAllByLoanId(loanEntity.getId());
        List<ProjectEntity> saveList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(oldProjectEntities)) {
            saveList.addAll(oldProjectEntities.stream()
                    .filter(entity -> !projectIds.contains(entity.getId()))
                    .peek(entity -> entity.setLoanId(null))
                    .collect(Collectors.toList()));
        }
        List<ProjectEntity> projectEntities = projectEntityRepo.findAllById(projectIds);
        if (projectEntities.size() != projectIds.size()) {
            throw new BusinessException(Code.NODATA);
        }
        projectEntities.forEach(projectEntity -> projectEntity.setLoanId(loanEntity.getId()));
        saveList.addAll(projectEntities);
        boolean sameSchool = true;
        String schoolId = null;
        for (ProjectEntity projectEntity : saveList) {
            if (null == schoolId) {
                schoolId = projectEntity.getSchoolId();
            } else if (!schoolId.equals(projectEntity.getSchoolId())) {
                throw new BusinessException(Code.ERROR, "请选择同一学校的项目");
            }
        }
        projectEntityRepo.saveAll(saveList);
    }

    private LoanEntity loadEntity(LoanDTO loanDTO) {
        Optional<LoanEntity> loanEntityOptional = loanEntityRepo.findById(loanDTO.getId());
        if (!loanEntityOptional.isPresent()) {
            throw new BusinessException(Code.NODATA, "数据不存在");
        }
        LoanEntity loanEntity = loanEntityOptional.get();
        // copy属性
        CopyOptions copyOptions = CopyOptions.create();
        copyOptions.setIgnoreNullValue(true);
        BeanUtil.copyProperties(loanDTO, loanEntity, copyOptions);
        return loanEntity;
    }

    private LoanEntity create(LoanDTO loanDTO) {
        // 还未提交过
        LoanEntity loanEntity = new LoanEntity();
        BeanUtil.copyProperties(loanDTO, loanEntity);
        loanEntity.setBorrowerId(AuthenticationHolder.getUserId());
        if (null != loanEntity.getLenderId()) {
            UserEntity lender = userEntityRepo.findById(loanDTO.getLenderId()).orElse(null);
            if (null == lender) {
                throw new BusinessException(Code.NODATA, "金融机构不存在");
            }
        }
        if (!CollectionUtils.isEmpty(loanDTO.getProjectIds()) && loanDTO.getProjectIds().size() > 5) {
            throw new BusinessException(Code.PARAMETER_ERROR, "关联项目不能超过5个");
        }
        return loanEntity;
    }

    private LoanEntity loadOrCreate(LoanDTO loanDTO) {
        if (StringUtils.isNotBlank(loanDTO.getId())) {
            return loadEntity(loanDTO);
        } else {
            return create(loanDTO);
        }
    }

    @Override
    @Transactional
    public BaseResult<?> apply(LoanDTO loanDTO) {
        LoanEntity loanEntity = this.loadOrCreate(loanDTO);
        if (null != loanEntity.getStatus() && !LoanStatus.CREATING.equals(loanEntity.getStatus())) {
            throw new BusinessException(Code.DUPLICATE_APPLICATION);
        }
        if (StringUtils.isBlank(loanEntity.getLenderId())) {
            return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "金融机构不能为空");
        }
        if (null == loanEntity.getLoanAmount()) {
            return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "贷款金额不能为空");
        }
        if (StringUtils.isBlank(loanEntity.getPurpose())) {
            return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "用途说明不能为空");
        }
        if (StringUtils.isBlank(loanEntity.getId())) {
            // 直接创建申请
            if (CollectionUtil.isEmpty(loanDTO.getAttachIdList())) {
                return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "资产汇总表不能为空");
            }
            List<String> projectIds = loanDTO.getProjectIds();
            if (CollectionUtils.isEmpty(projectIds)) {
                return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "项目不能为空");
            }
        } else {
            // 草稿申请
            List<String> attachIds = !CollectionUtils.isEmpty(loanDTO.getAttachIdList()) ? loanDTO.getAttachIdList() :
                    attachmentService.getAttachment(loanEntity.getId(), AttachType.ASSET_SUMMARY_LIST).stream().map(AttachVO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(attachIds)) {
                return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "资产汇总表不能为空");
            }
            List<String> projectIds = !CollectionUtils.isEmpty(loanDTO.getProjectIds()) ? loanDTO.getAttachIdList() :
                    projectEntityRepo.findAllByLoanId(loanEntity.getId()).stream().map(ProjectEntity::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(projectIds)) {
                return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "项目不能为空");
            }
        }
        return this.doApply(loanEntity, loanDTO);
    }

    /**
     * 创建申请
     *
     * @param loanEntity
     * @return
     */
    private BaseResult<String> doApply(LoanEntity loanEntity, LoanDTO loanDTO) {
        // 设置状态
        loanEntity.setStatus(LoanStatus.AUDITING);
        // 生成编号
        boolean success = false;
        for (int i = 0; i < 1000; i++) {
            String loanNo = genLoanNo();
            loanEntity.setLoanNo(loanNo);
            loanEntity.setCreateTime(String.valueOf(System.currentTimeMillis()));
            try {
                loanEntityRepo.save(loanEntity);
                success = true;
                break;
            } catch (ConstraintViolationException e) {
                log.error("创建融资贷款: {}异常: ", loanNo, e);
            }
        }
        if (!success) {
            log.error("创建融资贷款异常，尝试次数耗尽");
            return BaseResultFactory.produceResult(Code.ERROR, "请联系系统管理员");
        } else {
            if (!CollectionUtils.isEmpty(loanDTO.getAttachIdList())) {

                attachmentService.relateAttachment(loanEntity.getId(), loanDTO.getAttachIdList(), AttachType.ASSET_SUMMARY_LIST);
            }
            // 关联附件
            this.setAttach(loanEntity.getId(), loanDTO.getAttachIdList());
            // 关联项目
            this.setProject(loanEntity, loanDTO.getProjectIds());
            //   发起申请
            applicationService.create(ApplicationType.LOAN, loanEntity.getId(), new ArrayList<>(), loanEntity.getLenderId());
            return BaseResultFactory.produceResult(Code.SUCCESS, loanEntity.getId());
        }
    }

    @Override
    public LoanVO detail(String loanId) {
        LoanEntity loanEntity = this.findById(loanId);
        if (null == loanEntity) {
            return null;
        }
        LoanVO loanVO = new LoanVO();
        BeanUtil.copyProperties(loanEntity, loanVO);
        //机构信息
        UserEntity lender = loanEntity.getLender();
        if (null != lender) {
            loanVO.setLenderId(lender.getId());
            loanVO.setLenderName(lender.getEnterpriseName());
        }
        // 项目信息
        List<ProjectEntity> projects = loanEntity.getProjects();
        List<LoanDetailProjectVO> voList = projects.stream()
                .map(this::toLoanDetailProjectVo).collect(Collectors.toList());
        loanVO.setProjects(voList);
        // 附件信息
        loanVO.setAttachVOList(attachmentService.getAttachment(loanEntity.getId(), Arrays.asList(AttachType.ASSET_SUMMARY_LIST)));
        if (loanEntity.getStatus().equals(LoanStatus.FAIL)) {
            // 备注
            AuditEntity audit = applicationService.getLatestAuditByBizIdAndType(loanEntity.getId(), ApplicationType.LOAN);
            if (null != audit) {
                loanVO.setStatusDesc(audit.getRemark());
            }
        }
        return loanVO;
    }

    private LoanDetailProjectVO toLoanDetailProjectVo(ProjectEntity projectEntity) {
        LoanDetailProjectVO vo = new LoanDetailProjectVO();
        BeanUtil.copyProperties(projectEntity, vo);
        List<AttachVO> attachment = attachmentService.getAttachment(projectEntity.getId(), AttachType.BID_DOCUMENT);
        if (!CollectionUtils.isEmpty(attachment)) {
            AttachVO attachVO = attachment.get(0);
            vo.setBidFileName(attachVO.getName());
            vo.setBidUrl(attachVO.getUrl());
        }
        return vo;
    }

    @Override
    @Transactional
    public LoanApplyDetailVO applyDetail(String loanId) {
        LoanEntity loanEntity = this.findById(loanId);
        if (null == loanEntity || LoanStatus.CREATING.equals(loanEntity.getStatus())) {
            return null;
        }
        if (!AuthenticationHolder.isAdmin() && !AuthenticationHolder.getUserId().equals(loanEntity.getLenderId())) {
            return null;
        }
        LoanApplyDetailVO loanApplyDetailVO = new LoanApplyDetailVO();
        // 融资贷款信息
        LoanApplyDetailVO.LoanSimpleVO loanSimpleVO = new LoanApplyDetailVO.LoanSimpleVO();
        loanApplyDetailVO.setLoanInfo(loanSimpleVO);
        BeanUtil.copyProperties(loanEntity, loanSimpleVO);
        // 贷款人信息
        UserEntity borrower = loanEntity.getBorrower();
        if (null != borrower) {
            loanSimpleVO.setBorrowerEnterpriseName(borrower.getEnterpriseName());
        }
        // 融资贷款附件信息
        Optional<AttachVO> firstAttachVOOpt = attachmentService.getAttachment(loanEntity.getId(),
                Arrays.asList(AttachType.ASSET_SUMMARY_LIST)).stream().findFirst();
        firstAttachVOOpt.ifPresent(attachVO -> {
            loanSimpleVO.setAssetSummaryFileUrl(attachVO.getUrl());
            loanSimpleVO.setAssetSummaryFileName(attachVO.getName());
        });

        // 关联项目信息
        List<ProjectEntity> projects = loanEntity.getProjects();
        List<LoanDetailProjectVO> projectSimpleVOList = projects.stream()
                .map(this::toLoanDetailProjectVo).collect(Collectors.toList());
        loanApplyDetailVO.setProjectInfos(projectSimpleVOList);

        // 申请信息
        ApplicationVO applicationVO = applicationService.getValidApplicationDetailByBizTypeId(ApplicationType.LOAN, loanId);
        LoanApplyDetailVO.ApplicationSimpleVO applicationSimpleVO = new LoanApplyDetailVO.ApplicationSimpleVO();
        loanApplyDetailVO.setApplicationInfo(applicationSimpleVO);
        BeanUtil.copyProperties(applicationVO, applicationSimpleVO);

        // 放款信息
        ApplicationVO issueApplicationVO = applicationService.getValidApplicationDetailByBizTypeId(ApplicationType.ISSUE_LOAN, loanId);
        LoanApplyDetailVO.ApplicationSimpleVO issueApplicationSimpleVO = new LoanApplyDetailVO.ApplicationSimpleVO();
        loanApplyDetailVO.setIssueInfo(issueApplicationSimpleVO);
        BeanUtil.copyProperties(issueApplicationVO, issueApplicationSimpleVO);
        return loanApplyDetailVO;
    }

    /**
     * 查找
     *
     * @param id
     * @return
     */
    private LoanEntity findById(String id) {
        if (AuthenticationHolder.isAdmin()) {
            Optional<LoanEntity> loanEntityOptional = loanEntityRepo.findById(id);
            return loanEntityOptional.orElse(null);
        } else if (AuthenticationHolder.getUserAuth().getRoleTypes().contains(RoleType.FINANCIAL_INSTITUTIONS.name())) {
            return loanEntityRepo.findByIdAndLenderId(id, AuthenticationHolder.getUserId());
        } else {
            return loanEntityRepo.findByIdAndBorrowerId(id, AuthenticationHolder.getUserId());
        }
    }

    @Override
    @Transactional
    public void delete(String loanId) {
        LoanEntity loanEntity = this.findById(loanId);
        if (null == loanEntity) {
            return;
        }
        // 删除附件
        attachmentService.deleteAttachment(loanId, AttachType.ASSET_SUMMARY_LIST);
        // 删除申请
        applicationService.deleteByBizId(loanId);
        loanEntityRepo.delete(loanEntity);
    }

    @Override
    public PageResult<LoanListVO> search(LoanQueryDTO loanQueryDTO, Pageable pageable) {
        pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by(Sort.Direction.DESC, "createTime"));
        Specification<LoanEntity> specification = this.getSpec(loanQueryDTO);
        Page<LoanEntity> entityPage = loanEntityRepo.findAll(specification, pageable);
        long totalElements = entityPage.getTotalElements();
        List<LoanListVO> content = entityPage.getContent().stream()
                .map(loanEntity -> {
                    LoanListVO loanListVO = new LoanListVO();
                    BeanUtil.copyProperties(loanEntity, loanListVO);
                    // 贷款人/运营商家信息
                    UserEntity borrower = loanEntity.getBorrower();
                    if (null != borrower) {
                        loanListVO.setBorrowerId(borrower.getId());
                        loanListVO.setBorrowerName(borrower.getEnterpriseName());
                    }
                    //机构信息
                    UserEntity lender = loanEntity.getLender();
                    if (null != lender) {
                        loanListVO.setLenderId(lender.getId());
                        loanListVO.setLenderName(lender.getEnterpriseName());
                    }
                    // 项目信息
                    List<ProjectEntity> projects = loanEntity.getProjects();
                    StringBuilder scNameBuilder = new StringBuilder();
                    StringBuilder scIdBuilder = new StringBuilder();
                    List<ProjectStatusQueryVO> voList = projects.stream().map(entity -> {
                        if (scNameBuilder.length() == 0) {
                            scNameBuilder.append(entity.getBelongSchool());
                            scIdBuilder.append(entity.getSchoolId());
                        }
                        ProjectStatusQueryVO vo = new ProjectStatusQueryVO();
                        BeanUtil.copyProperties(entity, vo);
                        return vo;
                    }).collect(Collectors.toList());
                    loanListVO.setProjectSchoolId(scIdBuilder.toString());
                    loanListVO.setProjectSchoolName(scNameBuilder.toString());
                    loanListVO.setProjects(voList);
                    return loanListVO;
                }).collect(Collectors.toList());

        PageResult<LoanListVO> result = new PageResult<>();
        result.setElements(content);
        result.setTotalSize(totalElements);
        return result;
    }

    private Specification<LoanEntity> getSpec(LoanQueryDTO loanQueryDTO) {
        return (root, query, criteriaBuilder) -> {
            List<Predicate> predicateList = new ArrayList<>();

            if (AuthenticationHolder.isAdmin()) {
                // 管理员查询
                if (StringUtils.isNotBlank(loanQueryDTO.getBorrowerId())) {
                    predicateList.add(criteriaBuilder.equal(root.get("borrowerId"), loanQueryDTO.getBorrowerId()));
                }
                if (StringUtils.isNotBlank(loanQueryDTO.getLenderId())) {
                    predicateList.add(criteriaBuilder.equal(root.get("lenderId"), loanQueryDTO.getLenderId()));
                }
                predicateList.add(criteriaBuilder.notEqual(root.get("status"), LoanStatus.CREATING));
            } else if (AuthenticationHolder.getUserAuth().getRoleTypes().contains(RoleType.FINANCIAL_INSTITUTIONS.name())) {
                // 金融机构查询
                if (StringUtils.isNotBlank(loanQueryDTO.getBorrowerId())) {
                    predicateList.add(criteriaBuilder.equal(root.get("borrowerId"), loanQueryDTO.getBorrowerId()));
                }
                predicateList.add(criteriaBuilder.equal(root.get("lenderId"), AuthenticationHolder.getUserId()));
                predicateList.add(criteriaBuilder.notEqual(root.get("status"), LoanStatus.CREATING));
            } else {
                // 商家查询
                if (StringUtils.isNotBlank(loanQueryDTO.getLenderId())) {
                    predicateList.add(criteriaBuilder.equal(root.get("lenderId"), loanQueryDTO.getLenderId()));
                }
                predicateList.add(criteriaBuilder.equal(root.get("borrowerId"), AuthenticationHolder.getUserId()));
            }
            if (StringUtils.isNotBlank(loanQueryDTO.getValue())) {
                List<Predicate> like = new ArrayList<>();
                //编号
                like.add(criteriaBuilder.like(root.get("loanNo"), "%" + loanQueryDTO.getValue() + "%"));
                // 项目
                Join<LoanEntity, ProjectEntity> projectJoin = root.join(root.getModel().getSingularAttribute("projects", ProjectEntity.class), JoinType.LEFT);
                like.add(criteriaBuilder.like(projectJoin.get("name"), "%" + loanQueryDTO.getValue() + "%"));
                // 所属学校
                like.add(criteriaBuilder.like(projectJoin.get("belongSchool"), "%" + loanQueryDTO.getValue() + "%"));
                // 对接机构
                Join<LoanEntity, UserEntity> lenderJoin = root.join(root.getModel().getSingularAttribute("lender", UserEntity.class), JoinType.LEFT);
                like.add(criteriaBuilder.like(lenderJoin.get("enterpriseName"), "%" + loanQueryDTO.getValue() + "%"));

                Predicate[] predicates = new Predicate[like.size()];
                predicateList.add(criteriaBuilder.or(like.toArray(predicates)));
            }
            if (null != loanQueryDTO.getLoanStatus()) {
                predicateList.add(criteriaBuilder.equal(root.get("status"), loanQueryDTO.getLoanStatus()));
            }

            Predicate[] predicates = new Predicate[predicateList.size()];
            predicateList.toArray(predicates);
            return criteriaBuilder.and(predicates);
        };
    }

    @Override
    public List<LoanFiExportVO> fiExport(LoanQueryDTO loanQueryDTO) {
        Specification<LoanEntity> specification = this.getSpec(loanQueryDTO);
        List<LoanEntity> loanEntities = loanEntityRepo.findAll(specification);
        return toFiExportVO(loanEntities);
    }

    private List<LoanFiExportVO> toFiExportVO(List<LoanEntity> loanEntities) {
        if (CollectionUtils.isEmpty(loanEntities)) {
            return new ArrayList<>();
        }
        return loanEntities.stream()
                .map(loanEntity -> {
                    LoanFiExportVO loanFiExportVO = new LoanFiExportVO();
                    BeanUtil.copyProperties(loanEntity, loanFiExportVO);
                    // 贷款人/运营商家信息
                    UserEntity borrower = loanEntity.getBorrower();
                    if (null != borrower) {
                        loanFiExportVO.setBorrowerId(borrower.getId());
                        loanFiExportVO.setBorrowerName(borrower.getEnterpriseName());
                    }
                    List<ProjectEntity> projects = loanEntity.getProjects();
                    String projectNames = projects.stream().map(ProjectEntity::getName).collect(Collectors.joining(","));
                    loanFiExportVO.setProjectNames(projectNames);
                    loanFiExportVO.setProjectSchoolName(projects.get(0).getBelongSchool());
                    loanFiExportVO.setCreateTime(new Date(Long.parseLong(loanEntity.getCreateTime())));
                    loanFiExportVO.setStatus(loanEntity.getStatus().getDesc());
                    return loanFiExportVO;
                }).collect(Collectors.toList());
    }

    @Override
    public List<BorrowerLoanAdminExportVO> adminExportBorrowerLoan(LoanQueryDTO loanQueryDTO) {
        Specification<LoanEntity> specification = this.getSpec(loanQueryDTO);
        List<LoanEntity> loanEntities = loanEntityRepo.findAll(specification);
        return toBorrowerLoanAdminExportVO(loanEntities);
    }

    private List<BorrowerLoanAdminExportVO> toBorrowerLoanAdminExportVO(List<LoanEntity> loanEntities) {
        if (CollectionUtils.isEmpty(loanEntities)) {
            return new ArrayList<>();
        }
        return loanEntities.stream()
                .map(loanEntity -> {
                    BorrowerLoanAdminExportVO adminExportVO = new BorrowerLoanAdminExportVO();
                    BeanUtil.copyProperties(loanEntity, adminExportVO);
                    // 借款人/金融机构信息
                    UserEntity lender = loanEntity.getLender();
                    if (null != lender) {
                        adminExportVO.setLenderId(lender.getId());
                        adminExportVO.setLenderName(lender.getEnterpriseName());
                    }
                    //  项目信息
                    List<ProjectEntity> projects = loanEntity.getProjects();
                    String projectNames = projects.stream().map(ProjectEntity::getName).collect(Collectors.joining(","));
                    adminExportVO.setProjectNames(projectNames);
                    adminExportVO.setProjectSchoolName(projects.get(0).getBelongSchool());
                    adminExportVO.setCreateTime(new Date(Long.parseLong(loanEntity.getCreateTime())));
                    adminExportVO.setStatus(loanEntity.getStatus().getDesc());
                    return adminExportVO;
                }).collect(Collectors.toList());
    }

    @Override
    public List<LenderLoanAdminExportVO> adminExportLenderLoan(LoanQueryDTO loanQueryDTO) {
        Specification<LoanEntity> specification = this.getSpec(loanQueryDTO);
        List<LoanEntity> loanEntities = loanEntityRepo.findAll(specification);
        return toLenderLoanAdminExportVO(loanEntities);
    }

    private List<LenderLoanAdminExportVO> toLenderLoanAdminExportVO(List<LoanEntity> loanEntities) {
        if (CollectionUtils.isEmpty(loanEntities)) {
            return new ArrayList<>();
        }
        return loanEntities.stream()
                .map(loanEntity -> {
                    LenderLoanAdminExportVO adminExportVO = new LenderLoanAdminExportVO();
                    BeanUtil.copyProperties(loanEntity, adminExportVO);
                    // 贷款人/运营商家信息
                    UserEntity borrower = loanEntity.getBorrower();
                    if (null != borrower) {
                        adminExportVO.setBorrowerId(borrower.getId());
                        adminExportVO.setBorrowerName(borrower.getEnterpriseName());
                    }
                    //  项目信息
                    List<ProjectEntity> projects = loanEntity.getProjects();
                    String projectNames = projects.stream().map(ProjectEntity::getName).collect(Collectors.joining(","));
                    adminExportVO.setProjectNames(projectNames);
                    adminExportVO.setProjectSchoolName(projects.get(0).getBelongSchool());
                    adminExportVO.setCreateTime(new Date(Long.parseLong(loanEntity.getCreateTime())));
                    adminExportVO.setStatus(loanEntity.getStatus().getDesc());
                    return adminExportVO;
                }).collect(Collectors.toList());
    }

    @Override
    public List<LoanAdminExportVO> adminExport(List<String> ids, String value) {
        List<LoanEntity> loanEntities;
        if (!CollectionUtils.isEmpty(ids)) {
            loanEntities = loanEntityRepo.findAllByIdInAndStatusNotOrderByCreateTimeDesc(ids, LoanStatus.CREATING);
        } else if (StringUtils.isNotBlank(value)) {
            LoanQueryDTO loanQueryDTO = new LoanQueryDTO();
            loanQueryDTO.setValue(value);
            Specification<LoanEntity> specification = this.getSpec(loanQueryDTO);
            loanEntities = loanEntityRepo.findAll(specification, Sort.by(Sort.Direction.DESC, "createTime"));
        } else {
            loanEntities = loanEntityRepo.findAllByStatusNotOrderByCreateTimeDesc(LoanStatus.CREATING);
        }
        return toAdminExportVO(loanEntities);
    }

    private List<LoanAdminExportVO> toAdminExportVO(List<LoanEntity> loanEntities) {
        if (CollectionUtils.isEmpty(loanEntities)) {
            return new ArrayList<>();
        }
        return loanEntities.stream()
                .map(loanEntity -> {
                    LoanAdminExportVO adminExportVO = new LoanAdminExportVO();
                    BeanUtil.copyProperties(loanEntity, adminExportVO);
                    // 借款人/金融机构信息
                    UserEntity lender = loanEntity.getLender();
                    if (null != lender) {
                        adminExportVO.setLenderId(lender.getId());
                        adminExportVO.setLenderName(lender.getEnterpriseName());
                    }
                    // 贷款人/运营商家信息
                    UserEntity borrower = loanEntity.getBorrower();
                    if (null != borrower) {
                        adminExportVO.setBorrowerId(borrower.getId());
                        adminExportVO.setBorrowerName(borrower.getEnterpriseName());
                    }
                    // 项目信息
                    List<ProjectEntity> projects = loanEntity.getProjects();
                    String projectNames = projects.stream().map(ProjectEntity::getName).collect(Collectors.joining(","));
                    adminExportVO.setProjectNames(projectNames);
                    adminExportVO.setProjectSchoolName(projects.get(0).getBelongSchool());
                    adminExportVO.setCreateTime(new Date(Long.parseLong(loanEntity.getCreateTime())));
                    adminExportVO.setStatus(loanEntity.getStatus().getDesc());
                    return adminExportVO;
                }).collect(Collectors.toList());
    }

    @Override
    public String issuedLoanAmount(String userId) {
        userId = StringUtils.isBlank(userId) ? AuthenticationHolder.getUserId() : userId;
        Double amount = loanEntityRepo.sumLoanAmountByLenderIdAndStatusIn(userId,
                Arrays.asList(LoanStatus.WAIT_MAKE_LOAN, LoanStatus.WAIT_ACCEPT_LOAN, LoanStatus.FLOW_END));
        if (null == amount) {
            amount = NumberUtils.DOUBLE_ZERO;
        }
        return NumberUtil.roundStr(amount, 0);
    }

    @Override
    public Long countBorrower() {
        Long count = loanEntityRepo.countDistinctBorrowerIdByLenderIdAndStatusIsNot(AuthenticationHolder.getUserId(), LoanStatus.CREATING);
        if (null == count) {
            count = NumberUtils.LONG_ZERO;
        }
        return count;
    }

    @Override
    public Long countNeedAudit(String userId) {
        userId = StringUtils.isBlank(userId) ? AuthenticationHolder.getUserId() : userId;
        Long count = loanEntityRepo.countByLenderIdAndStatus(userId, LoanStatus.AUDITING);
        if (null == count) {
            count = NumberUtils.LONG_ZERO;
        }
        return count;
    }

    @Override
    public Long countAudited() {
        Long count = loanEntityRepo.countByLenderIdAndStatusIn(AuthenticationHolder.getUserId(),
                Arrays.asList(LoanStatus.FAIL, LoanStatus.WAIT_MAKE_LOAN, LoanStatus.WAIT_ACCEPT_LOAN, LoanStatus.FLOW_END));
        if (null == count) {
            count = NumberUtils.LONG_ZERO;
        }
        return count;
    }

    @Override
    public LoanDraftVO getDraft(String loanId) {
        LoanVO detail = this.detail(loanId);
        LoanDraftVO loanDraftVO = new LoanDraftVO();
        BeanUtil.copyProperties(detail, loanDraftVO);
        return loanDraftVO;
    }

    @Override
    @Transactional
    public void issueLoan(LoanIssueDTO loanIssueDTO) {
        // 保存
        LoanEntity loanEntity = loanEntityRepo.findById(loanIssueDTO.getId()).orElseThrow(() -> new BusinessException(Code.NODATA));
        if (!loanEntity.getLenderId().equals(AuthenticationHolder.getUserId())) {
            throw new BusinessException(Code.NODATA);
        }
        loanEntity.setIssueAmount(loanIssueDTO.getIssueAmount());
        loanEntity.setIssueTime(String.valueOf(System.currentTimeMillis()));
        loanEntity.setStatus(LoanStatus.WAIT_ACCEPT_LOAN);
        // 创建申请
        applicationService.create(ApplicationType.ISSUE_LOAN, loanEntity.getId(), new ArrayList<>(), loanEntity.getBorrowerId());
    }

    @Override
    @Transactional
    public void confirm(String loanId) {
        LoanEntity loanEntity = loanEntityRepo.findById(loanId).orElseThrow(() -> new BusinessException(Code.NODATA));
        if (!loanEntity.getBorrowerId().equals(AuthenticationHolder.getUserId())) {
            throw new BusinessException(Code.NODATA);
        }
        ApplicationEntity applicationEntity = applicationEntityRepo.findTopByBizIdAndTypeAndEnabledOrderByCreateTimeDesc(loanId, ApplicationType.ISSUE_LOAN, true);
        if (null == applicationEntity) {
            throw new BusinessException(Code.NODATA);
        }
        if (ApplicationStatus.PROCESSED.equals(applicationEntity.getStatus())) {
            throw new BusinessException(Code.ERROR, "已收款，请勿重复处理");
        }
        AuditDTO auditDTO = new AuditDTO();
        auditDTO.setApplicationId(applicationEntity.getId());
        auditDTO.setAuditResult(AuditResult.PASSED);
        auditDTO.setRemark("放款金额：" + NumberUtil.roundStr(loanEntity.getIssueAmount(), 0) + "¥");
        applicationService.audit(auditDTO);
    }

    private static String genLoanNo() {
        String date = DateUtil.format(new Date(), "yyyyMMdd");
        int i = RandomUtil.randomInt(1, 999);
        return date + StringUtils.leftPad(String.valueOf(i), 3, "0");
    }
}
